<template>
  <div class="goods-sku">
    <dl v-for="(item,index) in specs" :key="index">
      <dt>{{item.name}}</dt>
      <dd>
        <template v-for="(tag ,i) in item.values" :key="i">
          <img @click="toggle(tag,item.values)" v-if="tag.picture" :class="{selected:tag.selected,disabled:tag.disabled}" :src="tag.picture" alt="">
          <span @click="toggle(tag,item.values)" v-else :class="{selected:tag.selected,disabled:tag.disabled}">{{tag.name}}</span>
        </template>

      </dd>
    </dl>
  </div>
</template>
<script>
import powerSet from '@/vendor/power-set.js'
const spliter = '#'

// 获取选中的所有的规格
const useSelectedSpecs = (specs) => {
  const result = []
  specs.forEach((item, index) => {
    // 获取每一种规格选中的对象
    const current = item.values.find(tag => tag.selected)
    if (current) {
      // 该规格选中了，放到数组的指定位置
      result[index] = current.name
    } else {
      // 该规格没有选中，默认填充undefined
      result[index] = undefined
    }
  })
  return result
}

// 封装一个函数：生成路径字典
const usePathMap = (skus) => {
  const result = {}
  // 1.获取有效sku信息
  // 2.计算每一种sku的笛卡尔集
  // 3.把笛卡尔集合并生成字典
  skus.forEach(sku => {
    // 过滤无效的（没有库存）sku信息
    if (sku.inventory === 0) return
    // 获取sku的规格集合 specSet = [蓝色, 中国, 10cm]
    const specSet = sku.specs.map(item => item.valueName)
    // 计算每一个集合的笛卡尔集（二维数组）
    const subSets = powerSet(specSet)
    // 基于笛卡尔集生成路径字典
    // 需要把笛卡尔集中的每一项数据拼接为一个字符串作为key添加到路径字典中
    subSets.forEach(item => {
      // 排除空集
      if (item.length === 0) return
      // 拼接路径的key: pathKey = '蓝色#日本'
      const pathKey = item.join(spliter)
      if (result[pathKey]) {
        // 已经存在该key
        result[pathKey].push(sku.id)
      } else {
        // 尚不存在
        result[pathKey] = [sku.id]
      }
    })
  })

  return result
}

// 初始化的时候，判断每一个标签是否应该被禁用
// const initCheckSpecStatus = (specs, pathMap) => {
//   // 路径字典
//   // const pathMap = usePathMap(skus)
//   // 遍历每一种规格
//   specs.forEach(item => {
//     item.values.forEach(tag => {
//       // 判断规格是否在路径字典中存在，如果不存在应该被禁用
//       // 如果该规格不在路径字典中，添加一个属性disabled，值为true
//       tag.disabled = !pathMap[tag.name]
//     })
//   })
//   console.log(specs)
// }

// 点击任意规格时，判断按钮的状态（遍历所有的规格）
const clickCheckSpecStatus = (specs, pathMap) => {
  // 生成路径字典
  // const pathMap = usePathMap(skus)
  specs.forEach((item, i) => {
    // 遍历：颜色、产地、尺寸
    // selectedValues = [蓝色, undefined, 10cm]
    // 这里得到的值必须是点击选中的值
    const selectedValues = useSelectedSpecs(specs)
    item.values.forEach(tag => {
      if (tag.selected) {
        // 如果标签本身就是选中的，那么不需要判断禁用状态
        return
      } else {
        // 把没有选中的规格组合进去进行判断(判断所有规格的组合情况)
        selectedValues[i] = tag.name
      }

      // 过滤出有效值（选中的值）
      const validValues = selectedValues.filter(item => item)
      if (validValues.length > 0) {
        // 需要把选中的值组合成一个pathKey: 蓝色#10cm
        const pathKey = validValues.join(spliter)
        // 判断当前选中的值，是否在有效的路径字典中
        tag.disabled = !pathMap[pathKey]
      }
    })
  })
}

// 根据skuId控制规格的默认选中
const useDefaultSelectedSpec = (skuId, skus, specs) => {
  // skuId 表示要购买的商品的skuId
  // skus 表示后端返回的所有的sku信息
  // specs 表示遍历出来的所有的规格信息
  // 获取所有需要选中的规格：[蓝色 中国 10cm]
  const currentSku = skus.find(item => item.id === skuId)
  const targetSpec = currentSku.specs.map(item => item.valueName)
  // 思路：遍历每一个规格标签，判断是否需要被选中
  specs.forEach(item => {
    item.values.forEach(tag => {
      // 判断每个规格是否要被选中
      if (targetSpec.includes(tag.name)) {
        tag.selected = true
      }
    })
  })
}

export default {
  name: 'GoodsSku',
  props: {
    skuId: {
      type: String,
      default: ''
    },
    skus: {
      type: Array,
      default: () => []
    },
    specs: {
      type: Array,
      default: () => []
    }
  },
  setup (props, { emit }) {
    // 测试路径字典
    const pathMap = usePathMap(props.skus)
    // 控制工具skuId选中默认规格
    if (props.skuId) {
      useDefaultSelectedSpec(props.skuId, props.skus, props.specs)
    }

    // 初始化时，检测标签的状态
    clickCheckSpecStatus(props.specs, pathMap)

    // 控制规格的选中操作
    const toggle = (tag, list) => {
      // 禁用状态的规格不可以点击
      if (tag.disabled) return
      // 需求是：每一行只能选中一个：取消其他标签的选中，当前标签取反
      list.forEach(item => {
        // 排除当前标签(除去当前点击的标签之外的所有标签都取消选中)
        if (tag !== item) {
          item.selected = false
        }
      })
      // Vue3中直接添加的属性就是响应式（Vue2不是）this.$set(this.obj, 'abc', 123)
      tag.selected = !tag.selected

      // const ret = useSelectedSpecs(props.specs)
      // console.log(ret) // [蓝色, undefined, 10cm]

      // 点击判断每个规格的禁用状态
      clickCheckSpecStatus(props.specs, pathMap)
      // 获取选中的规格相关的结果：skuId，价格和库存相关信息
      // 判断是否所有的规格都选中了
      const sv = useSelectedSpecs(props.specs)
      if (sv.every(item => item)) {
        // 规格都选择了，获取规格相关信息
        // 使用选中的规格拼接一个路径key
        const pathKey = sv.join(spliter)
        // 获取当前购买商品的skuId
        const skuId = pathMap[pathKey][0]
        // 根据skuId获取商品信息
        const info = props.skus.find(item => item.id === skuId)

        // let specText = ''
        // info.specs.forEach(item => {
        //   specText += `${item.name}：${item.valueName} `
        // })

        const specText = info.specs.reduce((result, item) => result + `${item.name}：${item.valueName} `, '')

        // 选中规格后的商品信息
        const skuInfo = {
          skuId: skuId,
          oldPrice: info.oldPrice,
          price: info.price,
          inventory: info.inventory,
          specText: specText
        }
        // 把这个信息传递给父组件
        emit('sku-Info', skuInfo)
      } else {
        // 没有全部选中
        emit('sku-Info', null)
      }
    }
    return { toggle }
  }
}
</script>
<style scoped lang="less">
.sku-state-mixin () {
  border: 1px solid #e4e4e4;
  margin-right: 10px;
  cursor: pointer;
  &.selected {
    border-color: @xtxColor;
  }
  &.disabled {
    opacity: 0.6;
    border-style: dashed;
    cursor: not-allowed;
  }
}
.goods-sku {
  padding-left: 10px;
  padding-top: 20px;
  dl {
    display: flex;
    padding-bottom: 20px;
    align-items: center;
    dt {
      width: 50px;
      color: #999;
    }
    dd {
      flex: 1;
      color: #666;
      > img {
        width: 50px;
        height: 50px;
        .sku-state-mixin ();
      }
      > span {
        display: inline-block;
        height: 30px;
        line-height: 28px;
        padding: 0 20px;
        .sku-state-mixin ();
      }
    }
  }
}
</style>
